﻿using Shininglore.XAuth.Models;
using log4net;
using Shininglore.Security;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using Thrift.Server;
using Thrift.Transport;

namespace Shininglore.XAuth
{
    class AuthManager
    {
        // Create a logger for use in this class
        private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
        private static AuthManager instance = new AuthManager();

        private bool cancelled = false;
        TServer server;

        public static AuthManager GetInstance()
        {
            return instance;
        }

        public void Run()
        {
            AppDomain.CurrentDomain.UnhandledException += Program.CurrentDomain_UnhandledException;
            log.Info("Register AppDomain.UnhandledException to handle unexcepted error properly.");

            Console.CancelKeyPress += Console_CancelKeyPress;
            log.Info("Register Console.CancelKeyPress to handle exit event properly.");
            log.Info("Press CTRL+C to exit program.");

            var currentHash = GetLatestHash();

            try
            {
                AuthServiceHandler handler = new AuthServiceHandler(currentHash);
                AuthService.Processor processor = new AuthService.Processor(handler);

                // TODO: use SSL
                // https://issues.apache.org/jira/browse/THRIFT-181
                TServerTransport serverTransport = new TServerSocket(9090);

                // Use this for a multithreaded server
                server = new TThreadPoolServer(processor, serverTransport);

                log.Info("Starting the thrift server...");
                server.Serve();
                log.Info("Stopping the thrift server");
            }
            catch (Exception e)
            {
                log.Error("Failing processing the thrift request.", e);
            }
        }

        private string GetLatestHash()
        {
            using (AuthContext dc = new AuthContext())
            {
                var hash = dc.HashData.OrderByDescending(p => p.CreatedTime).FirstOrDefault();
                if (hash == null)
                    throw new ApplicationException("There is no available hash in database. Please initial database before any use.");
                return hash.Hash;
            }
        }

        private void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
        {
            log.Info("ConsoleCancelKeyPress signals.");
            e.Cancel = true;

            if (!cancelled)
            {
                cancelled = true;

                if (server != null)
                {
                    server.Stop();
                    log.Info("Try to stop the thrift server.");
                }
            }
        }
    }
}
